home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 126-150 / disk_136 / iff2pcs / source / pzuser.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  19KB  |  696 lines

  1. #include "pz.h"
  2.  
  3. /* Ali Ozer
  4. ** Main user interface/action loop for IFF2PCS
  5. ** AND a whole lot more...
  6. ** This file shouldn't be this long, but unfortunately, it is...
  7. ** It is also a bit messy (too many extern references, ack!)
  8. ** Nov 1987
  9. */
  10.     
  11. /* We assume several things:
  12. **  puzph = puzpw
  13. **  picx = integer multiple of (puzpw)
  14. **  picy = integer multiple of (puzph)
  15. */
  16. extern int puzpn, puzdepth;         /* These are the parameters for a piece */
  17. extern int picx, picy;              /* Where the picture is */
  18. extern int picw, pich;              /* The size of the picture */
  19. extern int textcolor;
  20. extern int bordercolor;
  21. extern int normcolor;
  22. extern int nonzerocolor;
  23. struct BitMap bgbm, rotbm;    /* Background bitmap, rotation bitmap */
  24.  
  25. extern struct PopUp_Menu pzmenu;
  26.  
  27. unsigned long starttime;      /* In seconds */
  28.  
  29. int minmousex, maxmousex, minmousey, maxmousey;
  30.  
  31. int puzph, puzpw;
  32. int picxbase, picybase; /* Simply picx-puzpw/2 and picy-puzph/2 */
  33.  
  34. extern struct BitMap picbm; 
  35.  
  36. struct BitMap   *wbm;
  37. struct RastPort *wrp;
  38.  
  39. struct Window *picwin;
  40. struct Screen *picscr;
  41.  
  42. int winoffset;  /* Offset of the puzzle area within the window */
  43.  
  44. int numpieces, numx, numy;
  45.  
  46. int toppiece, bottompiece;
  47.  
  48. /* Number of pieces will be (picw / puzpw) * (pich / puzph)
  49. */
  50.  
  51. struct piecestr {
  52.   int xloc, yloc;             /* Pixel location on screen */
  53.   int next, prev;             /* Next piece, in top to bottom sorted order */  
  54.   int rotation;               /* 0 normal, 1 ninety cw, 2 upsidedown, 3 90ccw */
  55.   int ingrid;                 /* True if piece is in the puzzle somewhere... */
  56. } *pieces;                    /* Bottompiece -> Prev -> Prev -> ... -> -1  */
  57.  
  58. ubyte *gridinfo;  /* Whether a grid piece is occupied or not... */
  59.  
  60. DrawGrid ()
  61. {
  62.     long x = picx-1;
  63.     long y = picy-1;
  64.     int cnt;
  65.  
  66.     SetAPen (wrp, (long)bordercolor);  
  67.     for (cnt = 0; cnt <= numy; cnt++) {
  68.       Move (wrp, x, y); Draw (wrp, x + picw + 1, y);
  69.       Move (wrp, x, y+1); Draw (wrp, x + picw + 1, y+1);
  70.       y += puzph;
  71.     };
  72.  
  73.     y = picy-1;
  74.     for (cnt = 0; cnt <= numx; cnt++) {
  75.       Move (wrp, x, y); Draw (wrp, x, y + pich + 1);
  76.       Move (wrp, x+1, y); Draw (wrp, x+1, y + pich + 1);
  77.       x += puzpw;
  78.     };
  79. }
  80.  
  81.  
  82. static ubyte tmp[8];  /* Temp for rotates... */
  83.  
  84. Rotate (plane, nbytes)     /* n is the side of the square in bytes... */
  85. ubyte *plane;
  86. int nbytes;
  87. {
  88.    int cnt, side, n, nbytec = nbytes << 3;
  89.    ubyte *s1, *s2, *s3, *s4;
  90.  
  91.    for (n = nbytes; n > 1; n -= 2) {
  92.      s1 = plane;
  93.      s2 = plane + n - 1;
  94.      s4 = s1 + nbytec * (n - 1);
  95.      s3 = s4 + n - 1;
  96.      for (side = 0; side < n-1; side++) {
  97.        for (cnt = 0; cnt < 8; cnt++) tmp[cnt] = s1[cnt * nbytes];
  98.        flip (s4, nbytes, s1, nbytes);
  99.        flip (s3, nbytes, s4, nbytes);
  100.        flip (s2, nbytes, s3, nbytes);
  101.        flip (&tmp[0], 1, s2, nbytes);
  102.        s1++; s3--; s2 += nbytec; s4 -= nbytec;
  103.      };
  104.      plane += (nbytec + 1);
  105.    }
  106. }
  107.  
  108.  
  109. /* Border modes */
  110. #define NOBORDER     0
  111. #define BORDER       1
  112. #define HLBORDER     2  /* Highlighted border */
  113. #define ERASE        3
  114. #define JUSTBORDER   4
  115.  
  116.  
  117. /* Come in with x = -1 to use the pieces default position...
  118. */
  119. DrawPiece (pnum, x, y, border)
  120. int border, x, y, pnum;
  121. {
  122.     long cnt;
  123.     int rot;
  124.     int bmx = (pnum % numx) * puzpw;   
  125.     int bmy = (pnum / numx) * puzph;
  126.  
  127.     if (x == -1) {
  128.       x = pieces[pnum].xloc;
  129.       y = pieces[pnum].yloc;
  130.     };
  131.  
  132.     if (border == ERASE || border == JUSTBORDER) {
  133.       SetAPen (wrp, 0L);
  134.       RectFill (wrp, (long)x, (long)y, (long)(x+puzpw-1), (long)(y+puzph-1));
  135.     } else {
  136.       if (pieces[pnum].rotation) {
  137.          SavePuzBM (&picbm, bmx, bmy, &rotbm);  
  138.          for (rot = 0; rot < pieces[pnum].rotation; rot++)
  139.            for (cnt = 0; cnt < rotbm.Depth; cnt++) 
  140.           Rotate (rotbm.Planes[cnt], puzph >> 3);
  141.          CopyFromBMToBM (&rotbm, 0, 0, wbm, x, y, puzpw, puzph);
  142.       } else CopyFromBMToBM (&picbm, bmx, bmy, wbm, x, y, puzpw, puzph);
  143.     };
  144.  
  145.     if (border != ERASE) {
  146.       if (border != NOBORDER) {
  147.         if (border == HLBORDER) SetAPen (wrp, (long)textcolor); 
  148.         else SetAPen (wrp, (long)bordercolor);
  149.         Move (wrp, (long)x,         (long)y);
  150.         Draw (wrp, (long)x+puzpw-1, (long)y);
  151.         Draw (wrp, (long)x+puzpw-1, (long)y+puzph-1);
  152.         Draw (wrp, (long)x,         (long)y+puzph-1);
  153.         Draw (wrp, (long)x,         (long)y);             
  154.       }
  155.     }
  156. }
  157.  
  158.  
  159. int RndInt();
  160. int Min ();
  161. int Max ();
  162. unsigned long TimeInSecs ();
  163.  
  164. int PuzzleSolved ()
  165. {
  166.   int width = (picw >> 3);
  167.   int planecnt, bytecnt, rowcnt;
  168.   unsigned char *curplane;
  169.  
  170.   for (planecnt = 0; planecnt < wbm->Depth; planecnt++) {
  171.     curplane = (unsigned char *)(wbm->Planes[planecnt]) + winoffset;
  172.     for (rowcnt = 0; rowcnt < pich; rowcnt++) {
  173.       for (bytecnt = 0; bytecnt < width; bytecnt++) {
  174.         if (*(curplane+bytecnt)) return (false);
  175.       }
  176.       curplane += wbm->BytesPerRow;
  177.     }
  178.   }
  179.   return (true);
  180. }
  181.  
  182.  
  183. CheckPuzzle ()
  184. {
  185.   int solved;
  186.   unsigned long timedif = TimeInSecs() - starttime;
  187.   static char *solvestr = "Time:  0:00:00   *** Puzzle is SOLVED ***";
  188.  
  189.   XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
  190.   if (timedif >= 360000) solvestr[5] = '0' + (timedif / 360000) % 10;
  191.   if (timedif >= 36000)  solvestr[6] = '0' + (timedif / 36000) % 10;
  192.   solvestr[7]  = '0' + (timedif / 3600) % 10;
  193.   solvestr[9]  = '0' + (timedif / 600) % 6;
  194.   solvestr[10] = '0' + (timedif / 60) % 10;
  195.   solvestr[12] = '0' + (timedif / 10) % 6;
  196.   solvestr[13] = '0' + (timedif % 10);
  197.   
  198.   SetWindowTitles (picwin, NULL, "Checking...");
  199.   if (solved = PuzzleSolved()) {
  200.     solvestr[14] = ' '; 
  201.     XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);      
  202.   } else solvestr[14] = '\0';
  203.   SetWindowTitles (picwin, NULL, solvestr);
  204.   Wait (1L << picwin->UserPort->mp_SigBit);
  205.   if (solved == false) XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
  206.   SetWindowTitles (picwin, NULL, PROGNAME);
  207. }
  208.  
  209.       
  210.     
  211. void MakePuzzle ()
  212. {
  213.   int cnt, miny, maxy, minx, maxx;
  214.  
  215.   /* Puzzle piece size. Puzpn is the power of two size of each piece.
  216.   ** For now, pieces have to be square, so we set puzph = puzpw.
  217.   */
  218.  
  219.   /* Minimum and maximum locations for puzzle pieces */
  220.   miny = picy + pich + 4; 
  221.   maxy = picwin->Height - puzph - 4;
  222.   minx = 2;
  223.   maxx = picwin->Width - puzpw - 2;
  224.  
  225.   minmousex = 0;
  226.   maxmousex = picscr->Width - puzpw - 1;
  227.   minmousey = picscr->BarHeight + 1;
  228.   maxmousey = picscr->Height - puzph - 1;
  229.  
  230.   if (((pieces = (struct piecestr *)
  231.          AllocMem ((long)(numpieces * sizeof(struct piecestr)), 0L)) == NULL) ||
  232.       ((gridinfo = (ubyte *) 
  233.          AllocMem ((long)(((numx * numy) >> 3) + 1), MEMF_CLEAR)) == NULL)) {
  234.     FreeBMs ();
  235.     Panic ("No memory for bitmaps");
  236.   };
  237.  
  238.   DrawGrid ();
  239.  
  240.   for (cnt = 0; cnt < numpieces; cnt++) {
  241.     /* piecexnum = cnt % numx   AND   pieceynum = cnt / numx */
  242.     pieces[cnt].ingrid = false;
  243.     pieces[cnt].rotation = RndInt (0, 3);
  244.     pieces[cnt].next = cnt + 1;
  245.     pieces[cnt].prev = cnt - 1;
  246.     pieces[cnt].xloc = RndInt (minx, maxx);
  247.     pieces[cnt].yloc = RndInt (miny, maxy);
  248.   };
  249.  
  250.   pieces[numpieces-1].next = -1;
  251.   bottompiece = numpieces - 1;
  252.   toppiece = 0;
  253.  
  254.   /* Shuffle some so that we don't always get the same order... */
  255.   for (cnt = 0; cnt < (numpieces>>3); cnt++) 
  256.     PutPieceAtTop (RndInt(0, numpieces-1));
  257.  
  258.   DrawAllPieces ();
  259. }
  260.  
  261.  
  262.  
  263. PutPieceAtTop (piece)
  264. int piece;
  265. {
  266.   if (pieces[piece].next != -1) 
  267.      pieces[pieces[piece].next].prev = pieces[piece].prev;
  268.   else 
  269.      bottompiece = pieces[piece].prev;
  270.   if (pieces[piece].prev != -1) 
  271.      pieces[pieces[piece].prev].next = pieces[piece].next;
  272.   else
  273.      toppiece = pieces[piece].next;
  274.   pieces[piece].next = toppiece;
  275.   pieces[toppiece].prev = piece;
  276.   toppiece = piece;
  277.   pieces[piece].prev = -1;
  278. }
  279.  
  280.  
  281. SeeIfInGrid (piece, newx, newy)
  282. int piece, newx, newy;
  283. {
  284.   if ((newx <= picx + picw) && (newx >= picx - puzpw) &&
  285.       (newy <= picy + pich) && (newy >= picy - puzph)) {
  286.      if (newx < picxbase) newx = picxbase; 
  287.      else if (newx >= picxbase + picw) newx = picxbase + picw - 1;
  288.      if (newy < picybase) newy = picybase;
  289.      else if (newy >= picybase + pich) newy = picybase + pich - 1;
  290.      newx = ((newx - picxbase) / puzpw) * puzpw + picx;
  291.      newy = ((newy - picybase) / puzph) * puzph + picy;
  292.      if (GridBoxOccupied (newx, newy, -1) == false) {
  293.        GridBoxOccupied (newx, newy, true);
  294.        pieces[piece].ingrid = true;
  295.        pieces[piece].xloc = newx;
  296.        pieces[piece].yloc = newy;
  297.      } else SeeIfInGrid (piece, pieces[piece].xloc, pieces[piece].yloc);
  298.   } else {
  299.      pieces[piece].ingrid = false;
  300.      pieces[piece].xloc = newx;
  301.      pieces[piece].yloc = newy;
  302.   }
  303. }
  304.     
  305.     
  306. /* Draws pieces that overlap the specified area in any way. Then grows the
  307. ** specified area by the bounding box of the new piece. A rather inefficient
  308. ** way of fixing up the picture after a change... The argument notpiece
  309. ** specifies a piece (if any) that does not need to be redrawn. Set to -1 if
  310. ** no such piece.
  311. */
  312. /*
  313. ReDrawThePiecesAt (x1, x2, y1, y2, notpiece)
  314. int x1, x2, y1, y2, notpiece;
  315. {
  316.   int cnt = bottompiece;
  317.   cnt = bottompiece;
  318.   while (cnt != -1) {
  319.     if ((pieces[cnt].xloc <= x2) && (pieces[cnt].xloc+puzpw-1 >= x1) &&
  320.         (pieces[cnt].yloc <= y2) && (pieces[cnt].yloc+puzph-1 >= y1) &&
  321.         (cnt != notpiece)) {
  322.       DrawPiece (cnt, -1, -1, BORDER);
  323.       x1 = Min (x1, pieces[cnt].xloc);
  324.       x2 = Max (x2, pieces[cnt].xloc+puzpw-1);
  325.       y1 = Min (y1, pieces[cnt].yloc);
  326.       y2 = Max (y2, pieces[cnt].yloc+puzph-1);
  327.     };
  328.     cnt = pieces[cnt].prev;
  329.   }
  330. }
  331. */
  332.  
  333.  
  334. ReDrawThePiecesAt (x1, x2, y1, y2, notpiece)
  335. int x1, x2, y1, y2, notpiece;
  336. {
  337.   int cnt = bottompiece, i, tmpprev;
  338.   for (i = 0; i < numpieces; i++) {
  339.     tmpprev = pieces[cnt].prev;      
  340.     if ((pieces[cnt].xloc <= x2) && (pieces[cnt].xloc+puzpw-1 >= x1) &&
  341.         (pieces[cnt].yloc <= y2) && (pieces[cnt].yloc+puzph-1 >= y1) &&
  342.         (cnt != notpiece)) {
  343.       DrawPiece (cnt, -1, -1, BORDER);
  344.       PutPieceAtTop (cnt);
  345.     };
  346.     cnt = tmpprev;
  347.   }
  348. }
  349.  
  350.  
  351. ErasePiece (piece)
  352. int piece;
  353. {
  354.   if (pieces[piece].ingrid == true) {
  355.     DrawPiece (piece, -1, -1, JUSTBORDER);
  356.     GridBoxOccupied (pieces[piece].xloc, pieces[piece].yloc, false);
  357.     pieces[piece].ingrid = false;
  358.   } else {
  359.     DrawPiece (piece, -1, -1, ERASE);
  360.     ReDrawThePiecesAt (pieces[piece].xloc, pieces[piece].xloc + puzph - 1,
  361.                        pieces[piece].yloc, pieces[piece].yloc + puzpw - 1, 
  362.                        piece);
  363.   }
  364. }
  365.  
  366.   
  367. DrawAllPieces ()
  368. {
  369.   int cnt = bottompiece;
  370.   while (cnt != -1) {
  371.     DrawPiece (cnt, -1, -1, BORDER);
  372.     cnt = pieces[cnt].prev;
  373.   };
  374. }
  375.  
  376.  
  377. FreeBMs ()
  378. {
  379.   FreeBM (&bgbm);
  380.   FreeBM (&rotbm);
  381.   if (gridinfo != NULL) FreeMem (gridinfo, (long)(((numx * numy) >> 3) + 1));
  382.   if (pieces != NULL) FreeMem (pieces, (long)(numpieces * sizeof(struct piecestr)));
  383. }
  384.  
  385.  
  386. /* Come in with x, y to test and possibly set the mode of the grid at location
  387. ** x, y. If mode is true or false, then the new mode is set. If mode is -1, then
  388. ** the old mode is returned...
  389. */
  390. int GridBoxOccupied (x, y, mode)
  391. int x, y, mode;
  392. {
  393.   int index;
  394.   ubyte bit;
  395.  
  396.   x = (x - picx) / puzpw;  
  397.   y = (y - picy) / puzph;
  398.   index = (y * numx + x) >> 3;
  399.   bit   = (1 << ((y * numx + x) & 7));
  400.   if (mode == true) gridinfo[index] |= bit;
  401.   else if (mode == false) gridinfo[index] &= ~bit;
  402.   else if ((gridinfo[index] & bit) != 0) return (true);
  403.   else return (false);
  404. }
  405.   
  406.  
  407. /* SavePuzBM will save the indicated section of bm in tmpbm; RestorePuzBM
  408. ** will bring that section back into the indicated section in bm.
  409. */
  410. SavePuzBM (bm, x, y, tmpbm)
  411. struct BitMap *bm, *tmpbm;
  412. int x, y;
  413. {
  414.   CopyFromBMToBM (bm, x, y, tmpbm, 0, 0, puzpw, puzph);
  415. }
  416.  
  417.  
  418. RestorePuzBM (bm, x, y, tmpbm)
  419. struct BitMap *bm, *tmpbm;
  420. int x, y;
  421. {
  422.   CopyFromBMToBM (tmpbm, 0, 0, bm, x, y, puzpw, puzph);
  423. }
  424.  
  425.  
  426. int PuzzlePieceAt (x, y)
  427. int x, y;
  428. {
  429.   int i = toppiece;
  430.   
  431.   while (i != -1) {
  432.     if ((pieces[i].xloc-1 <= x) &&
  433.         (pieces[i].xloc+puzpw >= x) &&
  434.         (pieces[i].yloc-1 <= y) &&
  435.         (pieces[i].yloc+puzph >= y)) return(i);
  436.     i = pieces[i].next;
  437.   }
  438.   return(-1);  /* Not on any piece... */
  439. }
  440.  
  441.  
  442. RotatePiece (piece)
  443. int piece;
  444. {
  445.   if (++(pieces[piece].rotation) > 3) pieces[piece].rotation = 0;
  446. }
  447.  
  448.  
  449. GetAndHandleEvents (win)
  450. struct Window *win;
  451. {
  452.   struct IntuiMessage *msg;
  453.   int mousemoved, selected;
  454.   ULONG class;
  455.   USHORT code;
  456.   int x, y, lastx, lasty, deltax, deltay, restorex, restorey, selectedpiece;
  457.  
  458.   picwin = win;
  459.   picscr = win->WScreen;
  460.   
  461.   wbm = &(picscr->BitMap);
  462.   wrp = win->RPort;
  463.  
  464.   CopyFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);      
  465.  
  466.   SetDrMd (wrp, JAM1);
  467.  
  468.   if ((puzpn = GetDifficulty(win)) == 0) Panic (NULL);
  469.  
  470.   SetAPen (wrp, 0L);
  471.   RectFill (wrp, 0L, (long)picy, (long)(win->Width-1), (long)(win->Height-1));
  472.  
  473.   puzph = puzpw = (1 << puzpn); 
  474.  
  475.   picxbase = picx - (puzpw >> 1);
  476.   picybase = picy - (puzph >> 1);
  477.  
  478.   pich = (pich >> puzpn) << puzpn;
  479.   picw = (picw >> puzpn) << puzpn;
  480.  
  481.   numx = (picw / puzpw);
  482.   numy = (pich / puzph);
  483.  
  484.   numpieces = numx * numy;
  485.  
  486.   winoffset = picy * wbm->BytesPerRow + (picx >> 3);  /* Offset in plane, in bytes */  
  487.  
  488.   if (InitBM (&bgbm, puzph, puzpw, puzdepth) == false || 
  489.       InitBM (&rotbm, puzph, puzpw, puzdepth) == false) {
  490.     FreeBMs ();
  491.     Panic ("Out of memory!");
  492.   };
  493.  
  494.   MakePuzzle ();
  495.  
  496.   selectedpiece = -1;
  497.  
  498.   starttime = TimeInSecs ();
  499.  
  500.   while (1) {
  501.  
  502.     mousemoved = false;
  503.  
  504.     while (msg = (struct IntuiMessage *) GetMsg (win->UserPort)) {
  505.  
  506.       class = msg->Class;
  507.       code  = msg->Code;
  508.       x     = msg->MouseX; 
  509.       y     = msg->MouseY;
  510.  
  511.       ReplyMsg (msg);
  512.   
  513.       switch (class) {
  514.  
  515.     case MENUPICK:
  516.       switch (ITEMNUM(code)) {
  517.             case 0: /* Show */ break;
  518.             case 1: /* New */  break;
  519.             case 2: /* Quit */
  520.           FreeBMs ();
  521.               return;  /* For now, MENUUP signifies EXIT */
  522.               break;
  523.           };
  524.       break;
  525.               
  526.     case MOUSEMOVE: 
  527.       mousemoved = true; 
  528.       break;
  529.  
  530.         case MOUSEBUTTONS: 
  531.           switch (code) {
  532.             case SELECTDOWN: 
  533.           lastx = x;
  534.               lasty = y;
  535.           if ((selectedpiece = PuzzlePieceAt (x, y)) != -1) {
  536.                 ReportMouse (TRUE, win);  /* Start telling us about mouse loc */
  537.         lastx  = pieces[selectedpiece].xloc;
  538.         deltax = lastx - x;
  539.         lasty  = pieces[selectedpiece].yloc;
  540.         deltay = lasty - y;
  541.                 ErasePiece (selectedpiece);
  542.                 SavePuzBM (wbm, lastx, lasty, &bgbm);      /* Save background */
  543.                 DrawPiece (selectedpiece, -1, -1, HLBORDER);
  544.             SavePuzBM (wbm, lastx, lasty, &rotbm);     /* Piece picked up */
  545.             mousemoved = true;
  546.               };
  547.               break;
  548.             case SELECTUP: 
  549.           if (selectedpiece != -1) {
  550.                 ReportMouse (FALSE, win); 
  551.                 RestorePuzBM (wbm, lastx, lasty, &bgbm);
  552.         PutPieceAtTop (selectedpiece);
  553.         SeeIfInGrid (selectedpiece, x+deltax, y+deltay);
  554.                 DrawPiece (selectedpiece, -1, -1, 
  555.                     (pieces[selectedpiece].ingrid == true ? NOBORDER : BORDER));
  556.         selectedpiece = -1;
  557.                 mousemoved = false;
  558.               };
  559.               break;
  560.             case MENUDOWN: 
  561.           if (selectedpiece != -1) {
  562.         RotatePiece (selectedpiece);
  563.                 DrawPiece (selectedpiece, lastx, lasty, HLBORDER);
  564.             SavePuzBM (wbm, lastx, lasty, &rotbm);     /* Piece picked up */
  565.               } else 
  566.                 switch (PopUp (&pzmenu, win)) {
  567.          case CHECKCMD:
  568.           CheckPuzzle ();
  569.                   break;               
  570.                  case SHOWCMD: 
  571.                    XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
  572.                  XORFromBMToBM (wbm, picx, picy, &picbm, 0, 0, picw, pich);    
  573.                      XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
  574.           Wait (1L << win->UserPort->mp_SigBit);
  575.                    XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
  576.                  XORFromBMToBM (wbm, picx, picy, &picbm, 0, 0, picw, pich);    
  577.                      XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
  578.           break;
  579.          case NEWCMD:  
  580. /*                SetWindowTitles (picwin, NULL, "Option not available yet");
  581. **                Wait (1L << picwin->UserPort->mp_SigBit);
  582. **                SetWindowTitles (picwin, NULL, PROGNAME);
  583. */                break;
  584.                  case HELPCMD: 
  585.           if (DoAboutBox (bordercolor, textcolor) == false) {
  586.                     SetWindowTitles (picwin, NULL, COPYRIGHT);
  587.                     Wait (1L << picwin->UserPort->mp_SigBit);
  588.                     SetWindowTitles (picwin, NULL, PROGNAME);
  589.                   };
  590.                   break;
  591.          case QUITCMD: 
  592.               FreeBMs ();
  593.                   return; 
  594.                   break;
  595.                  default:
  596.                   break;
  597.         };
  598.           break;
  599.             case MENUUP: 
  600.           break;
  601.             default:
  602.           break;
  603.           }; 
  604.       break;
  605.   
  606.         default: 
  607.       break;
  608.       }
  609.        
  610.     }
  611.  
  612.     if ((mousemoved == true) && (selectedpiece != -1)) {
  613.         restorex = lastx;
  614.         restorey = lasty;
  615.         lastx = x + deltax;
  616.         lasty = y + deltay;
  617.         if (lastx < minmousex) lastx = minmousex;
  618.         else if (lastx > maxmousex) lastx = maxmousex;
  619.         if (lasty < minmousey) lasty = minmousey;
  620.         else if (lasty > maxmousey) lasty = maxmousey;
  621.         deltax = lastx - x;
  622.         deltay = lasty - y;        
  623.         WaitBOVP (&(picscr->ViewPort));
  624.         RestorePuzBM (wbm, restorex, restorey, &bgbm);
  625.         SavePuzBM (wbm, lastx, lasty, &bgbm);
  626.         CopyFromBMToBM (&rotbm, 0, 0, wbm, lastx, lasty, puzpw, puzph);
  627.     Delay (2L);
  628.     };
  629.  
  630.     Wait (1L << win->UserPort->mp_SigBit);
  631.  
  632.   }
  633.  
  634. }
  635.  
  636.  
  637. /* Gadgets to get the difficulty from the user... 
  638. */
  639.  
  640. #define GADWIDTH  120
  641. #define GADHEIGHT 12
  642. #define GADX      400
  643. #define GADY      300
  644. #define NUMGADS   4
  645.  
  646. static struct Gadget pzgad[NUMGADS];
  647.  
  648. static struct Gadget samplegad = {
  649.   NULL, GADX, 0, GADWIDTH, GADHEIGHT,
  650.   GADGHBOX, RELVERIFY, BOOLGADGET, NULL, NULL, NULL, 0L, NULL, 0, NULL};
  651.  
  652. static char *gadtext[NUMGADS] = {
  653.   "Real easy", "Not so easy", "Difficult", "Quit"};
  654.  
  655. int GetDifficulty ()
  656. {
  657.   int cnt;
  658.   struct IntuiMessage *msg;
  659.  
  660.   SetAPen (wrp, (long)nonzerocolor);
  661.  
  662.   Move (wrp, (long)GADX-8, (long)GADY-8);
  663.   Text (wrp, "Select difficulty level:", 24L);
  664.  
  665.   for (cnt = 0; cnt < NUMGADS; cnt++) {
  666.     pzgad[cnt] = samplegad;  /* Structure copy */
  667.     pzgad[cnt].TopEdge = GADY+cnt*(GADHEIGHT+2)+(cnt == NUMGADS-1 ? 8 : 0);
  668.     if (cnt != NUMGADS-1) {
  669.       pzgad[cnt].GadgetID   = DIFF_EASY - cnt;
  670.       pzgad[cnt].NextGadget = &pzgad[cnt+1];
  671.     };
  672.     Move (wrp, (long)pzgad[cnt].LeftEdge+10, (long)pzgad[cnt].TopEdge+8);
  673.     Text (wrp, gadtext[cnt], (long)strlen(gadtext[cnt]));
  674.   }
  675.  
  676.   AddGList (picwin, pzgad, -1L, -1L, NULL);
  677. /*RefreshGList (picwin->FirstGadget, picwin, NULL, -1L);*/
  678.  
  679.   cnt = -1;
  680.   while (true) {
  681.     while (msg = (struct IntuiMessage *)GetMsg(picwin->UserPort)) {
  682.       if (msg->Class == GADGETUP && msg->IAddress != NULL) 
  683.         cnt = ((struct Gadget *)(msg->IAddress))->GadgetID;
  684.       ReplyMsg (msg);
  685.       if (cnt != -1) {
  686.          RemoveGList (picwin, pzgad, -1L);
  687.          return (cnt); 
  688.       }
  689.     }
  690.     Wait (1L << picwin->UserPort->mp_SigBit);
  691.   }
  692. }
  693.  
  694.  
  695.     
  696.